﻿using UnityEngine;
using System.Collections.Generic;

public class GameState : MonoBehaviour 
{	
	public enum State 
	{
		INIT,
		PLAY,
		SUCCESS,
		FAIL,
		RESTART,
		NEXT_LEVEL,
	};
	public State gameState = State.INIT;
	
	public class LevelData
	{				
		public List<Color> disc;
		public Queue<Color> balls;
		
		public LevelData()
		{
			disc = new List<Color>();
			balls = new Queue<Color>();
		}
		
		public bool CheckMembers()
		{	
			bool retVal = false;
			
			if (disc.Count == 3 && balls.Count > 0)
			{
				retVal = true;
			}
			
			return retVal;
		}
	};
	
	public class GameData
	{
		public Color targetColor = Color.white;
		
		private int currentLevel = 0;
		public List<LevelData> levels = new List<LevelData>();
		
		public Queue<Color> balls = new Queue<Color>();
		
		public List<Color> slices = new List<Color>();
		
		public Color GetNextBall()
		{
			Color col = Color.clear;
			
			if (balls.Count > 0)
			{			
				col = balls.Dequeue();
			}
			
			return col;
		}
		
		public void LoadLevel()
		{
			if (currentLevel < levels.Count)
			{
				LevelData l = levels[currentLevel];
				
				balls = new Queue<Color>(l.balls);
				slices = new List<Color>(l.disc);
			}
			else
			{
				Debug.LogError("currentLevel index out of range");
			}
		}
		
		public void LoadNextLevel()
		{				
			currentLevel = (++currentLevel) % levels.Count;
			
			LoadLevel();
		}
	}
	public GameData gameData = new GameData();
	
	private BallList ballList;	
	private SliceManager sliceManager;
	private InputManager inputManager;
	private BallColors ballColors;
	
	void Start() 
	{
		ballList = (BallList) GetComponent("BallList");
		sliceManager = (SliceManager) GetComponent("SliceManager");
		inputManager = (InputManager) GetComponent("InputManager");
		ballColors = (BallColors) GetComponent("BallColors");
	}
	
	void Update() 
	{
		switch (gameState) 
		{			
		case State.INIT:
			FetchLevelData();
			gameData.LoadLevel();
			sliceManager.SetSlices(gameData.slices);
			ballList.DestroyBalls();
			gameState = State.PLAY;
			break;
			
		case State.PLAY:			
			if (ballColors.IsMeshesTargetColor(sliceManager.slices, gameData.targetColor))
			{
				gameState = State.SUCCESS;				
			}			
			else if (gameData.balls.Count == 0 && ballList.balls.Count == 0)
			{
				gameState = State.FAIL;
			}			
			break;
			
		case State.SUCCESS:
			Debug.Log("Puzzle complete :) - Press Space / double tap for next level");
						
			if (inputManager.InputNextLevel())
			{
				gameState = State.NEXT_LEVEL;
			}
			
			break;	
			
		case State.FAIL:
			Debug.Log("Puzzle failed :( - Hit Space / double tap to retry...");			
			
			if (inputManager.InputNextLevel())
			{
				gameState = State.RESTART;
			}
			
			break;
			
		case State.RESTART:
			ballList.DestroyBalls();
			gameData.LoadLevel();			
			sliceManager.SetSlices(gameData.slices);
			gameState = State.PLAY;
			break;
			
		case State.NEXT_LEVEL:
			Debug.Log("Loading next level...");
			ballList.DestroyBalls();
			gameData.LoadNextLevel();
			sliceManager.SetSlices(gameData.slices);			
			gameState = State.PLAY;
			break;
		}
	}
		
	// ---Xml parsing---
	// -----------------
	private void FetchLevelData()
	{			
		TextAsset xmlData = new TextAsset();

        xmlData = (TextAsset)Resources.Load("levels", typeof(TextAsset));
		
		TinyXmlReader reader = new TinyXmlReader(xmlData.ToString());
		
		Debug.Log("FetchLevelData - Started");
		
		while (reader.Read())
		{	
			if (reader.tagName == "Level" && reader.isOpeningTag)
			{
				LevelData level = new LevelData();
				
				reader.Read();
				
				if (reader.tagName == "Disc" && reader.isOpeningTag)
				{
					while (reader.Read("Disc"))
					{
						if (reader.tagName == "Color" && reader.isOpeningTag)
						{
							Color col = ballColors.GetColorFromName(reader.content.ToString());
							if (col != Color.clear)
							{
								level.disc.Add(col);
							}
							else
							{
								Debug.Log ("FetchLevelData - Failed to add disc color");
							}
						}
					}
					
					reader.Read();
				}					
				
				if (reader.tagName == "Balls" && reader.isOpeningTag)
				{
					while (reader.Read("Balls"))
					{							
						if (reader.tagName == "Color" && reader.isOpeningTag)
						{
							Color col = ballColors.GetColorFromName(reader.content.ToString());
							if (col != Color.clear)
							{
								level.balls.Enqueue(col);
							}
							else
							{
								Debug.Log ("FetchLevelData - Failed to add ball color");
							}
						}
					}
				}
				
				if (level.CheckMembers())
				{
					gameData.levels.Add(level);
				}
				else
				{
					Debug.Log ("FetchLevelData - Failed to add level");
				}
			}
		}
	}
}
